﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Visio = Microsoft.Office.Interop.Visio;
using SPNetworkTopology.ExternalWindows.ViewModel;
using System.Windows;
using System.Globalization;
using System.IO;

namespace SPNetworkTopology
{
    class DropShapes : GetRecordSetRowIDS
    {       
        private string SPServerShapeName = "SPServer";
        private string SPFarmShapeName = "SPFarm";
        private string ServiceContainerShapeName = "Service Container";
        private string SPServiceShapeName = "Service Name";

        private Visio.Master SPServerShapeMaster;
        private Visio.Master SPFarmShapeMaster;
        private Visio.Master ServiceContainerShapeMaster;
        private Visio.Master SPServiceShapeShapeMaster;

        private string ServerPageName = "SharePoint Network Topolgy";
        private string ServicePageName = "{0} - Service Details";

        public DropShapes()
        {            
            if (base.IsConfigFileCorrupted)
            {
                MessageBox.Show(SPNetworkTopologyResource.ConfigFileErrorMessage,
                    SPNetworkTopologyResource.AddInName,
                    MessageBoxButton.OK,
                    MessageBoxImage.Error,
                    MessageBoxResult.OK,
                    MessageBoxOptions.DefaultDesktopOnly);

                return;
            }

            if (base.CurrentDocumentRecordSet == null)
            {
                MessageBox.Show(SPNetworkTopologyResource.RecordsetError,
                   SPNetworkTopologyResource.AddInName,
                   MessageBoxButton.OK,
                   MessageBoxImage.Error,
                   MessageBoxResult.OK,
                   MessageBoxOptions.DefaultDesktopOnly);

                return;
            }

            this.SetMasterShapes();
            this.DropServers();
            this.DropServices();
        }

        private void SetMasterShapes()
        {
            Visio.Masters spFarmMaster = GetStencil().Masters;
            Array shapes;
            spFarmMaster.GetNamesU(out shapes);
            this.SPServerShapeMaster = spFarmMaster.get_ItemU(this.SPServerShapeName);
            this.SPFarmShapeMaster = spFarmMaster.get_ItemU(this.SPFarmShapeName);
            this.ServiceContainerShapeMaster = spFarmMaster.get_ItemU(this.ServiceContainerShapeName);
            this.SPServiceShapeShapeMaster = spFarmMaster.get_ItemU(this.SPServiceShapeName);
        }

        /// <summary>
        /// Returns Stencil document - SharePoint Topology.vss
        /// </summary>
        /// <returns>Document object</returns>
        private Visio.Document GetStencil()
        {
            Visio.Document stencil = null;
            try
            {

                foreach (Visio.Document stencilDocument in VisioObjects.visApplication.Documents)
                {
                    if (stencilDocument.Name.Equals("SharePoint Topology.vss", StringComparison.OrdinalIgnoreCase))
                    {
                        stencil = stencilDocument;
                        break;
                    }
                }

                Utility utility = new Utility();
                if (stencil == null && File.Exists(utility.StencilName))
                {
                    Visio.Documents applicationDocuments = VisioObjects.visApplication.Documents;
                    stencil = applicationDocuments.OpenEx(utility.StencilName, Convert.ToInt16(Visio.VisOpenSaveArgs.visOpenDocked));
                }
            }
            catch (Exception err)
            {
                throw err;
            }
            return stencil;
        }

        /// <summary>
        /// Drop SharePoint servers
        /// </summary>
        private void DropServers()
        {
            Visio.Page spServerPage = null;
            Visio.Shape parentShape = null;
            List<string> pageNameCollection;

            try
            {
                spServerPage = base.VisioDocument.Pages[ServerPageName];
            }
            catch (Exception)
            {

            }

            //Create new page if the diagram has been on the shape already
            if (spServerPage == null || spServerPage.Shapes.Count > 0)
            {
                //Initialize the parameters
                pageNameCollection = new List<string>();
                int count = 1;

                //Collect the Page names
                foreach (Visio.Page currentPage in base.VisioDocument.Pages)
                {
                    pageNameCollection.Add(currentPage.Name);
                }               
                
                while (pageNameCollection.Contains(ServerPageName))
                {
                    ServerPageName = String.Concat("SharePoint Network Topolgy", "(", count.ToString(), ")");
                    count++;
                }

                spServerPage = base.VisioDocument.Pages.Add();
                spServerPage.Name = ServerPageName;
            }

            Array droppedShapeIDs = DropManyLinkedU(base.ServerRowIDList, this.SPServerShapeMaster, spServerPage);

            double spFarmPinX = 4;
            double spFarmPinY = 8;

            if (base.FarmRowID != int.MinValue)
            {
                parentShape = spServerPage.DropLinked(this.SPFarmShapeMaster, spFarmPinX, spFarmPinY, base.CurrentDocumentRecordSet.ID, base.FarmRowID, false);
            }
            else
            {
                parentShape = spServerPage.Drop(this.SPFarmShapeMaster, spFarmPinX, spFarmPinY);
            }

            for (int nextChildRowIndex = 0; nextChildRowIndex < droppedShapeIDs.Length; nextChildRowIndex++)
            {
                Visio.Shape childShape = spServerPage.Shapes.get_ItemFromID(int.Parse(droppedShapeIDs.GetValue(nextChildRowIndex).ToString()));

                if (parentShape != null && childShape != null)
                {
                    parentShape.AutoConnect(
                        childShape,
                        Visio.VisAutoConnectDir.visAutoConnectDirDown,
                        null);
                }
            }
        }

        /// <summary>
        /// Drop SharePoint Services
        /// </summary>
        private void DropServices()
        {
            IEnumerable<string> serverNameCollection = base.ServiceRowIDList.Select(ServerRowID => ServerRowID.ServerName).Distinct();
            List<string> pageNameCollection;
            
            foreach (string server in serverNameCollection)
            {
                string servicePageName = String.Format(this.ServicePageName, server);
                List<int> rowIDList = base.ServiceRowIDList.Where(val => val.ServerName.Equals(server)).Select(val => val.RowID).ToList();

                Visio.Page spServicePage = null;

                try
                {
                    spServicePage = base.VisioDocument.Pages[servicePageName];
                }
                catch (Exception)
                {

                }

                //Create new page if the diagram has been on the shape already
                if (spServicePage == null || spServicePage.Shapes.Count > 0)
                {
                    //Initialize the parameters
                    pageNameCollection = new List<string>();
                    int count = 1;                    

                    //Collect the Page names
                    foreach (Visio.Page currentPage in base.VisioDocument.Pages)
                    {
                        pageNameCollection.Add(currentPage.Name);
                    }

                    while (pageNameCollection.Contains(servicePageName))
                    {
                        servicePageName = String.Concat(String.Format(this.ServicePageName, server), "(", count.ToString(), ")");
                        count++;
                    }

                    spServicePage = base.VisioDocument.Pages.Add();
                    spServicePage.Name = servicePageName;
                }

                Array droppedShapeIDs = DropManyLinkedU(rowIDList, this.SPServiceShapeShapeMaster, spServicePage);

                double spServicePinX = 4.25;
                double spServicePinY = -23;

                //Drop the container shape
                Visio.Shape spServiceContainerShape = spServicePage.Drop(this.ServiceContainerShapeMaster, spServicePinX, spServicePinY);
                //Set the server name as shape text 
                spServiceContainerShape.Text = server;

                for (int nextChildRowIndex = 0; nextChildRowIndex < droppedShapeIDs.Length; nextChildRowIndex++)
                {
                    Visio.Shape childShape = spServicePage.Shapes.get_ItemFromID(int.Parse(droppedShapeIDs.GetValue(nextChildRowIndex).ToString()));

                    childShape.Text = base.ServiceRowIDList.Where(ServiceRowID =>
                        ServiceRowID.ServerName.Equals(server) && ServiceRowID.RowID.Equals(childShape.GetLinkedDataRow(base.CurrentDocumentRecordSet.ID))).
                        Select(ServiceRowID => ServiceRowID.ServiceName).FirstOrDefault();

                    spServiceContainerShape.ContainerProperties.InsertListMember(childShape, 1);
                }

                spServicePage.AutoSizeDrawing();
            }
        }

        private Array DropManyLinkedU(List<int> sourceRowID, Visio.Master masterShape, Visio.Page visioPage)
        {
            Array masterToDrop = Array.CreateInstance(typeof(object), sourceRowID.Count);
            // create an array for each location of each row
            Array pins = Array.CreateInstance(typeof(double), sourceRowID.Count * 2); // x and y pairs
            Random randGen = new Random();

            for (int nextRowIDIndex = 0; nextRowIDIndex < sourceRowID.Count; nextRowIDIndex++)
            {
                masterToDrop.SetValue(masterShape, nextRowIDIndex);

                // get the random pin x value based on the width of the target page
                pins.SetValue(
                    randGen.Next(0, 11), //(int)_VisioDocument.Pages[1].PageSheet.get_CellsU("PageWidth").ResultIU),
                    nextRowIDIndex * 2); // each x location in the array

                // get the random pin y value based on the height of the targer page
                pins.SetValue(
                    randGen.Next(0, 8), //(int)_VisioDocument.Pages[1].PageSheet.get_CellsU("PageHeight").ResultIU),
                    nextRowIDIndex * 2 + 1); // each y location in the array
            }

            Array rowIDsToDrop = sourceRowID.ToArray();
            Array droppedShapeIDs;

            var selectedService = ServiceLinking.SelectedService;

            visioPage.DropManyLinkedU(
                        ref masterToDrop,
                        ref pins,
                        CurrentDocumentRecordSet.ID,
                        ref rowIDsToDrop,
                        false,
                        out droppedShapeIDs);

            return droppedShapeIDs;
        }
    }
}


